package ru.ifmo.thesis.domain;

import ru.ifmo.thesis.quantities.Kilometers;

public class CachedGeoService extends AbstractGeoService {
	
	private static final int MAX_LOCATION = 1000;

	@SuppressWarnings("unchecked")
	private Kilometers<Double>[][] geoTable = new Kilometers[MAX_LOCATION][MAX_LOCATION];
	
	private Location[] cache = new Location[MAX_LOCATION];
	
	private int nextId = 0;
	
	//accepts office loc. params
	CachedGeoService(String address, double latitude, double longtitude) {
		setOfficeLocation(getLocation(address, latitude, longtitude));
	}
	
	/* (non-Javadoc)
	 * @see ru.ifmo.thesis.domain.IGeoService#distance(ru.ifmo.thesis.domain.Location, ru.ifmo.thesis.domain.Location)
	 */
	public Kilometers<Double> distance(Location first, Location second) {
		return geoTable[first.id][second.id];
	}
	
	/* (non-Javadoc)
	 * @see ru.ifmo.thesis.domain.IGeoService#getLocation(java.lang.String, double, double)
	 */
	public Location getLocation(String address, double latitude, double longtitude) {
		if (nextId >= MAX_LOCATION) {
			throw new IllegalStateException("Max locations reached");
		}
		
		int newId = generateId();

		Location result = new Location(newId, address, latitude, longtitude);
		cache[newId] = result;
		
		updateGeoTable(newId);
		
		return result;
	}

	private int generateId() {
		return nextId++;
	}

	private void updateGeoTable(int newId) {
		for (int i = 0; i < newId; i++) {
			geoTable[i][newId] = geoTable[newId][i] = distanceInternal(cache[i], cache[newId]);
		}
		geoTable[newId][newId] = new Kilometers<Double>(0d);
	}
	
}
